package com.example.loginserver.config;


import com.example.loginserver.filter.TokenFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import static com.example.loginserver.domain.Constant.LOGIN_QRCODE;

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Resource
    private AccessDeniedHandler accessDeniedHandler;

    @Resource
    private AuthenticationEntryPoint authenticationEntryPoint;

    @Resource
    private AuthenticationSuccessHandler authenticationSuccessHandler;

    @Resource
    private RedisTemplate<String, String> redisTemplate;



    public TokenFilter tokenFilter() throws Exception {
        return new TokenFilter(authenticationManagerBean(), redisTemplate);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("luo")
                .password(passwordEncoder().encode("1234"))
                .authorities("download");

    }

    /*private CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");    //同源配置，*表示任何请求都视为同源，若需指定ip和端口可以改为如“localhost：8080”，多个以“，”分隔；
        corsConfiguration.addAllowedHeader("*");    //header，允许哪些header，本案中使用的是token，此处可将*替换为token；
        corsConfiguration.addAllowedMethod("*");    //允许的请求方法，PSOT、GET等
        corsConfiguration.addExposedHeader("Authorization");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration); //配置允许跨域访问的url
        return source;
    }*/


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
//              允许spring security 相关的请求跨域
                .cors()
//                .configurationSource(corsConfigurationSource())
                .and()
                .authorizeRequests()
                .antMatchers("/login",LOGIN_QRCODE,"/download","/downloadEncryptedContent")
                .permitAll()
                .anyRequest().authenticated()
                .and()

                .formLogin()
                .loginProcessingUrl("/login")
                .passwordParameter("password")
                .usernameParameter("userName")
                .successHandler(authenticationSuccessHandler)

                .failureHandler((HttpServletRequest request,
                                 HttpServletResponse response, AuthenticationException exception) -> {
                    ObjectMapper objectMapper = new ObjectMapper();
                    ObjectNode node = objectMapper.createObjectNode();
                    node.put("code", 400);
                    node.put("msg", "登陆失败" + exception.getMessage());
                    response.setContentType("application/json;charset=UTF-8");
                    response.getOutputStream().write(objectMapper.writeValueAsBytes(node));
                })
//                .loginPage("https://www.bilibili.com")
//              必须要关闭 csrf 才能直接使用 loginProcessingUrl
                .and().csrf()
                .disable()

//                关闭session管理
                .sessionManagement()
//                一定要再这里关闭session，不然每次请求都会往 响应中添加 set-cookie 响应头
//                对 uniApp 有极大影响（因为uniApp不能调用cookie相关的api）
                .sessionCreationPolicy(SessionCreationPolicy.NEVER)
                .disable()

//                无权访问资源时，使用authenticationEntryPoint进行相应的处理
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler)
        ;

        http.addFilter(tokenFilter());
//        http.addFilterBefore(tokenFilter(), UsernamePasswordAuthenticationFilter.class);

    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        AuthenticationManager authenticationManager = super.authenticationManagerBean();

        return authenticationManager;
    }


}
